// general 通用的东西都放在这里

#pragma once
#ifndef GENERAL_H
#define GENERAL_H

// 网络编程头文件

// Windows环境下头文件
#ifdef _WIN32	
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib,"ws2_32.lib")
// Linux环境下头文件
#else
#include <sqlite3.h>        //sqlute3数据库
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>		// Linux进程等待
#include <errno.h>      	// 错误处理
#include <signal.h>     	// 信号
#include <sys/types.h>  	// 提供各种数据类型
#include <sys/socket.h> 	// 套结字函数和结构
#include <netinet/in.h> 	// sockaddr_in 结构
#include <arpa/inet.h>  	// IP 地址转换 htons
#include <netdb.h>      	// 域名转换 inet_ntop
#include <sys/ioctl.h>  	// I/O控制的函数
#include <sys/poll.h>   	// socket 等待测试机制
#include <unistd.h>     	// 标准IO，进程等等
#include <pwd.h>        	// 对系统某些文件的访问
#include <sys/epoll.h>		// epoll IO多路复用
#include <sys/stat.h>		// 获取文件信息
#include <fcntl.h>			// open 等关于文件的函数
#include <sys/sendfile.h>	// 零拷贝，在两个内核之间传输数据
#endif

// 跨平台通用头文件
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
#include <cassert>
#include <stdio.h>
#include <memory>
#include <ctime>
#include <atomic>
#include <mutex>
#include <algorithm>
#include <unordered_map>

const size_t LISTENQ = 1024;
const size_t MAXLINE = 4096; // 一行的最大长度

/*
INFO： 表示正常的日志输出，一切按预期运行。
WARNING： 表示警告，该事件不影响服务器运行，但存在风险。
ERROR： 表示发生了某种错误，但该事件不影响服务器继续运行。
FATAL： 表示发生了致命的错误，该事件将导致服务器停止运行。
*/
#define INFO    1
#define WARNING 2
#define ERROR   3
#define FATAL   4

// 输出事件日志 --参数顺序：日志等级/日志信息
// 输出顺序：cout--事件级别--事件发生的时间--事件信息--事件所在的文件--所在的行号--endl;
#define LOG(level, message) Log(#level, message, __FILE__, __LINE__)

// 自己的错误处理包装函数，只有发生严重错误时才调用它
// 先打印错误信息，然后 exit(-1)
void sys_error(const char* ptr)
{
	perror(ptr);
	exit(-1);
}

// 打印日志 --参数顺序：/日志等级/错误信息/文件名/行号/
static void Log(std::string level, std::string message, std::string file_name, int line)
{
	time_t curr_t = time(nullptr);				// 获取时间戳
	struct tm* curr_tm = gmtime(&curr_t);		// 把时间戳转换为 时区为 0 的时间结构
	curr_tm->tm_hour += 8;						// 小时 +8 才是东八区北京
	//const char* myformat = "%Y-%m-%d %H:%M:%S";	// 自己的输出格式
	const char* myformat = "%H:%M:%S";			// 定义自己的输出格式
	char mytime[25] = { 0 };					// 储存时间
	strftime(mytime, 25, myformat, curr_tm);	// 把时间结构按照自己的输出格式转换
	
	// 打印顺序：事件级别--事件发生的时间--事件信息--事件所在的文件--所在的行号--\n
	std::cout << "[" << level << "][" << mytime << "][" << message 
		<< "][" << file_name << "][" << line << "]" << std::endl;
}

#endif

